package dst.ass2.ejb.interceptor;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;

import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import dst.ass2.ejb.model.IAuditParameter;
import dst.ass2.ejb.model.impl.AuditLog;
import dst.ass2.ejb.model.impl.AuditParameter;

public class AuditInterceptor {

	@PersistenceContext
	private EntityManager entityManager;

	private final static Logger LOGGER = Logger.getLogger(AuditInterceptor.class.getName());
	
	//Defined in TaskManagementBean
	@AroundInvoke   //Defines an interceptor method that interposes on business methods  --> http://docs.oracle.com/javaee/6/api/javax/interceptor/AroundInvoke.html
	public Object interceptor(InvocationContext ctx) throws Exception {
		
		Date now=new Date();
		
		LOGGER.info("call interceptor on method "+ctx.getMethod().getName()+" @ "+now);	//Name of the Method invoked
		
		AuditLog auditLog = new AuditLog();		//make new AuditLog
		auditLog.setInvocationTime(now);			//set the time of invocation
		auditLog.setMethod(ctx.getMethod().getName());  //set the invoked method
		
		Object[] params = ctx.getParameters();		//retrieve the Parameters
		
		List<IAuditParameter> auditParameters=formatAndSetAuditParameters(params,auditLog);	//change the Parameters to List with AuditParameter 
		
		LOGGER.info("retrieved "+auditParameters.size()+" parameters");	//log size of parameters
		
		auditLog.setParameters(auditParameters);	//set tem in log

		Object result = null;  //check null values
		try {
			result = ctx.proceed();
			if(result!=null)
				auditLog.setResult(result.toString());		//get the result of the method
			else
				auditLog.setResult("null");

			return result;
		} catch (Exception e) {
			auditLog.setResult(e.toString());  //set Exception String as Result on an Error
			throw e;
		} finally {
			entityManager.persist(auditLog);
			entityManager.flush();
			LOGGER.info("log persisted");
		}
	}
	
	/**
	 * Goes through Parameters and Convert them to AuditParameter
	 * @return
	 */
	private List<IAuditParameter> formatAndSetAuditParameters(Object[] params, AuditLog auditLog){
		List<IAuditParameter> parameters = new LinkedList<IAuditParameter>();  //list of the parameters
		
		if(params!=null){
			for (int i = 0; i < params.length; i++) {		//iterate through Array of Paramaters
				Object parameterObject = params[i];		
	
				AuditParameter parameter = new AuditParameter();	//AuditParameter
				
				parameter.setAuditLog(auditLog);
				parameter.setParameterIndex(i);	//set the index
				
				if(parameterObject!=null){ //check null values
					parameter.setType(parameterObject.getClass().getName());  	//set
					parameter.setValue(parameterObject.toString());	//set
				}
				else{		
					parameter.setType("null");  	//set null	
					parameter.setValue("null");		//set null
				}
	
				parameters.add(parameter);		//add the new AuditParameter
			}
		}
		
		return parameters;
	}
	

}
